from django.db import models
from Login import models as login_models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey  # GenericRelation:不会生成字段，只用于反向查询
from utils.models_save import ModelsSave

# Create your models here.


__all__ = [
    "Environment",
    "Database",
    "Project",
    "Module",
    "Cases",
    "CasesDetail",
    "Attachment",
    "OftenMyTool"
]


# 工具表
class OftenMyTool(models.Model):
    title = models.CharField(max_length=200)
    URL = models.URLField()
    remark = models.CharField(max_length=1000)
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")


# 附件表
class Attachment(models.Model):
    file_name = models.CharField(max_length=32, verbose_name="附件名称")
    # file_format = models.IntegerField(choices=settings.MODELS_CHOICES['file_format'], verbose_name="附件格式")
    file_format = models.CharField(max_length=32, verbose_name="附件格式")
    file_size = models.IntegerField(verbose_name="附件大小")
    file_data = models.FileField(upload_to='Attachment/file_data', blank=True, null=True, verbose_name="附件内容")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    def save(self, *args, **kwargs):
        old_obj = Attachment.objects.filter(id=self.id).first()
        rets = ['file_data']
        ModelsSave(old_obj, self, rets).run()  # 删除旧数据
        super(Attachment, self).save(*args, **kwargs)

    class Meta:
        verbose_name = '附件表'
        verbose_name_plural = '附件表'

    def __str__(self):
        return self.file_name


# 环境表
class Environment(models.Model):
    env_protocol = models.CharField(max_length=20, default="http", verbose_name="请求协议")
    env_ip = models.CharField(max_length=20, verbose_name="IP地址")
    env_port = models.IntegerField(verbose_name="端口")
    env_domain = models.CharField(max_length=40, blank=True, null=True, verbose_name="域名")
    env_title = models.CharField(max_length=100, verbose_name="环境名称")
    token = models.CharField(max_length=320, blank=True, default='', verbose_name="环境token")
    local_storage = models.TextField(blank=True, null=True, default='', verbose_name="本地存储")
    session_storage = models.TextField(blank=True, null=True, default='', verbose_name="会话存储")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    class Meta:
        verbose_name = '环境表'
        verbose_name_plural = '环境表'

    def __str__(self):
        return self.env_title


# 数据库连接表
class Database(models.Model):
    db_type = models.IntegerField(choices=settings.MODELS_CHOICES['database']['db_type'], verbose_name="数据库类型")
    db_title = models.CharField(max_length=100, default="", verbose_name="标题")
    db_name = models.CharField(max_length=100, verbose_name="库名")
    db_ip = models.CharField(max_length=20, verbose_name="IP地址")
    db_port = models.IntegerField(verbose_name="端口号")
    db_user = models.CharField(max_length=20, verbose_name="用户名")
    db_password = models.CharField(max_length=20, blank=True, default='', verbose_name="密码")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    class Meta:
        verbose_name = '数据库连接表'
        verbose_name_plural = '数据库连接表'

    def __str__(self):
        return self.db_name


# SQL明细表，直接存储sql语句，有传入字段和传出字段
class SqlDetail(models.Model):
    sql_title = models.CharField(max_length=100, verbose_name="标题")
    database = models.ForeignKey(to='Database', on_delete=True, verbose_name='所属数据库')
    sql_push_fields = models.CharField(max_length=200, blank=True, null=True, verbose_name="入参")  # 入参模板，
    sql_pull_fields = models.CharField(max_length=200, blank=True, null=True, verbose_name="出参")  # 出参模板
    sql_template = models.TextField(blank=True, null=True, default=None, verbose_name='模板')
    sql_data = models.TextField(blank=True, null=True, default=None, verbose_name='合成sql')
    sql_test_data = models.FileField(upload_to='sqldetail/sql_test_data/%Y-%m', blank=True, null=True,
                                     verbose_name="测试结果")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    test_status = models.IntegerField(choices=settings.MODELS_CHOICES['test_status'], default=3, verbose_name="测试结果")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    def save(self, *args, **kwargs):
        old_obj = SqlDetail.objects.filter(id=self.id).first()
        rets = ['sql_test_data']
        ModelsSave(old_obj, self, rets).run()  # 删除旧数据
        super(SqlDetail, self).save(*args, **kwargs)

    class Meta:
        verbose_name = 'SQL明细表'
        verbose_name_plural = 'SQL明细表'

    def __str__(self):
        return self.sql_title


# 项目表
class Project(models.Model):
    name = models.CharField(unique=True, max_length=20, verbose_name="项目名")
    project_key = models.CharField(max_length=64, unique=True, blank=True, null=True, default=None,
                                   verbose_name='项目key')
    describe = models.CharField(max_length=200, blank=True, verbose_name="项目描述")  # 非必填
    database = models.ForeignKey('Database', on_delete=True, verbose_name="数据库连接表")
    environment = models.ForeignKey('Environment', on_delete=True, verbose_name="IP端口协议表")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    class Meta:
        verbose_name = '项目'
        verbose_name_plural = '项目'

    def __str__(self):
        return self.name


# 模块表
class Module(models.Model):
    project = models.ForeignKey('Project', on_delete=True, verbose_name="项目名称")
    name = models.CharField(max_length=40, verbose_name="模块名")
    testers = models.ForeignKey(login_models.Account, on_delete=models.CASCADE, related_name="测试人员",
                                verbose_name="测试人员")
    developer = models.ForeignKey(login_models.Account, on_delete=models.CASCADE, related_name="开发人员",
                                  verbose_name="开发人员")
    module_key = models.CharField(max_length=64, blank=True, null=True, default=None, verbose_name='模块key')
    describe = models.CharField(max_length=400, blank=True, verbose_name="模块描述")  # 非必填
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    class Meta:
        unique_together = ('project', 'module_key',)
        verbose_name = '模块'
        verbose_name_plural = '模块'

    def __str__(self):
        return self.name


# 用例表
class Cases(models.Model):
    test_person = models.ForeignKey(login_models.Account, on_delete=True, verbose_name="用例负责人")
    project = models.ForeignKey('Project', on_delete=True, default=1, verbose_name="所属项目")
    module = models.ForeignKey('Module', on_delete=True, verbose_name="所属模块")
    name = models.CharField(unique=True, max_length=100, verbose_name="用例标题")
    precondition = models.CharField(max_length=500, blank=True, null=True, default=None, verbose_name="预置条件")  # 非必填
    test_data = models.CharField(max_length=1000, blank=True, null=True, default=None, verbose_name="测试数据")  # 非必填
    test_steps = models.CharField(max_length=1000, blank=True, null=True, default=None, verbose_name="测试步骤")  # 非必填
    expected_results = models.CharField(max_length=1000, blank=True, null=True, verbose_name="预期结果")  # 非必填
    warehouse_data = models.FileField(upload_to='Cases/warehouse_data', blank=True, null=True, default=None,
                                      verbose_name="数据仓库")
    property = models.IntegerField(choices=settings.MODELS_CHOICES['cases']['property'], verbose_name="用例属性")
    level = models.IntegerField(choices=settings.MODELS_CHOICES['cases']['level'], verbose_name="重要级别")
    test_status = models.IntegerField(choices=settings.MODELS_CHOICES['test_status'], default=3, verbose_name="测试结果")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    execution_time = models.DateTimeField(blank=True, null=True, verbose_name="执行时间")
    exe_number = models.IntegerField(blank=True, null=True, verbose_name="执行次数")
    consume_time = models.FloatField(blank=True, null=True,verbose_name="耗时")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    def save(self, *args, **kwargs):
        project_obj = self.project
        module_obj = self.module
        module_project_obj = module_obj.project
        if project_obj.id != module_project_obj.id:
            raise ValueError("项目与模块不匹配")
        old_obj = Cases.objects.filter(id=self.id).first()
        rets = [
            'warehouse_data',
        ]
        ModelsSave(old_obj, self, rets).run()  # 删除旧数据
        super(Cases, self).save(*args, **kwargs)

    class Meta:
        verbose_name = '用例'
        verbose_name_plural = '用例'

    def __str__(self):
        return self.name


# 用例步骤表
class CasesDetail(models.Model):
    cases = models.ForeignKey('Cases', on_delete=True, verbose_name='关联用例表')
    title = models.CharField(max_length=200, verbose_name="步骤名称")
    sort = models.IntegerField(choices=settings.MODELS_CHOICES['sort'], verbose_name="步骤顺序")
    # 第一步 与ContentType建立外键
    content_type = models.ForeignKey(to=ContentType, on_delete=None)
    # 第二步 建一个字段保存对应表下的数据id
    object_id = models.IntegerField()
    # 第三步 绑定关系，不会生成字段
    content_object = GenericForeignKey("content_type", "object_id")
    steps_data_template = models.TextField(blank=True, null=True, default=None, verbose_name="步骤数据模板")
    steps_data = models.TextField(blank=True, null=True, default=None, verbose_name="步骤数据")
    error_info = models.TextField(blank=True, null=True, default=None, verbose_name="错误信息")
    create_time = models.DateTimeField(blank=True, null=True, verbose_name="创建日期")
    update_time = models.DateTimeField(blank=True, null=True, verbose_name="更新日期")
    execution_time = models.DateTimeField(blank=True, null=True, verbose_name="执行时间")
    consume_time = models.FloatField(blank=True, null=True, verbose_name="耗时")
    # exe_number = models.IntegerField(blank=True, null=True, verbose_name="执行次数")
    results = models.IntegerField(choices=settings.MODELS_CHOICES['results'], default=3, verbose_name='执行状态')
    assert_status = models.IntegerField(choices=settings.MODELS_CHOICES['results'], default=3, verbose_name='状态断言')
    test_status = models.IntegerField(choices=settings.MODELS_CHOICES['test_status'], default=3, verbose_name="测试结果")
    status = models.IntegerField(choices=settings.MODELS_CHOICES['common'], verbose_name="状态")

    class Meta:
        unique_together = ('cases', 'sort',)
        verbose_name = '用例步骤表'
        verbose_name_plural = '用例步骤表'

    def __str__(self):
        return self.title
